#include "Socket.h"
#include "InetAddress.h"
#include "Logger.h"

#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/tcp.h>

Socket::~Socket()
{
    Close();
}

void Socket::bindAddress(const InetAddress &localaddr)
{
    // 是否启用socket地址复用？

    if (0 != bind(sockfd_, (struct sockaddr *)localaddr.getSockAddr(), sizeof(struct sockaddr_in)))
    {
        LOG_FATAL("bind sockfd: %d error: %d: %s", sockfd_,errno,strerror(errno));
    }
}
void Socket::listen()
{
    if (0 != ::listen(sockfd_, 1024))
    {
        LOG_FATAL("listen sockfd: %d fail", sockfd_);
    }
}

int Socket::accept(InetAddress *peerAddr)
{
    /**
     * accept传入的长度，必须初始化
     * 需要将sockfd设置为非阻塞，两种方法：
     * 1.accept4
     * 2.编写一个setNonBlock函数，通过fcntl设置
    */
    struct sockaddr_in addr;
    socklen_t len=sizeof addr;
    // int connfd = ::accept(sockfd_, (struct sockaddr *)&addr, &len);
    int connfd = ::accept4(sockfd_, (struct sockaddr *)&addr, &len, SOCK_NONBLOCK | SOCK_CLOEXEC);
    if (connfd >= 0)
    {
        peerAddr->setSockAddr(addr);
    }
    return connfd;
}

void Socket::shutdownWrite()
{
    int ret = shutdown(sockfd_, SHUT_WR);
    if (ret < 0)
    {
        LOG_ERROR("shutdownWrite error: %d: %s", errno, strerror(errno));
    }
}

void Socket::Close()
{
    if(sockfd_>=0)
    {
        close(sockfd_);
        sockfd_=-1;
    }
}

void Socket::setTcpNoDelay(bool on)
{
    int optval = on ? 1 : 0;
    setsockopt(sockfd_, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof optval);
}

void Socket::setReuseAddr(bool on)
{
    int optval = on ? 1 : 0;
    setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval);
}

void Socket::setReusePort(bool on)
{
    int optval = on ? 1 : 0;
    setsockopt(sockfd_, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof optval);
}

void Socket::setKeepAlive(bool on)
{
    int optval = on ? 1 : 0;
    setsockopt(sockfd_, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof optval);
}